package cn.nkpro.elcube.cloud;

import org.apache.dubbo.config.spring.ReferenceBean;
import org.apache.dubbo.config.spring.util.SpringCompatUtils;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotationMetadata;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.HashMap;

/**
 * 抽象dubbo服务注册类
 */
public abstract class NkAbstractDubboConsumerAutoRegistrar implements ImportBeanDefinitionRegistrar {

    /**
     * 返回需要注册的接口
     */
    protected abstract Class<?>[] registrarClass();

    /**
     * 返回需要注册的dubbo组，即cloudId
     */
    protected List<String> cloudIds(Environment env) {
        List<String> cloudIds = new ArrayList<>();
        int index = 0;
        String group;
        while((group = env.getProperty(String.format("nk.cloud.provider-ids[%d]",index++)))!=null){
            cloudIds.add(group);
        }
        return cloudIds;
    }

    /**
     * 注册bean
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

        Environment env = ((DefaultListableBeanFactory) registry).getBean(Environment.class);

        for(String group : cloudIds(env)){
            for(Class<?> injectedType : registrarClass()){

                String interfaceName = injectedType.getName();
                String referenceBeanName = injectedType.getSimpleName()+"@"+group;

                Map<String,Object> attributes = new HashMap<>();
                attributes.put("id",referenceBeanName);
                attributes.put("group",group);
                attributes.put("version","1.0.0");
                attributes.put("interface",injectedType.getName());
                attributes.put("check",false);

                RootBeanDefinition beanDefinition = new RootBeanDefinition();
                beanDefinition.setBeanClassName(ReferenceBean.class.getName());
                beanDefinition.getPropertyValues().add("id", referenceBeanName);
                beanDefinition.setAttribute("referenceProps", attributes);
                beanDefinition.setAttribute("interfaceClass", injectedType);
                beanDefinition.setAttribute("interfaceName", interfaceName);
                GenericBeanDefinition targetDefinition = new GenericBeanDefinition();
                targetDefinition.setBeanClass(injectedType);
                String newBeanDesc = SpringCompatUtils.getPropertyValue(beanDefinition.getPropertyValues(), "id");
                beanDefinition.setDecoratedDefinition(new BeanDefinitionHolder(targetDefinition, newBeanDesc + "_decorated"));
                beanDefinition.setAttribute("factoryBeanObjectType", injectedType);
                registry.registerBeanDefinition(referenceBeanName, beanDefinition);
            }
        }
    }
}
